﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Mendel
{
    public class Item
    {
        private Data data;

        public string Name { get; set; }

        public DType Type { get { return data.Type; } }

        public RType Role { get; set; }

        public bool Constant { get; set; }

        

        private ReaderWriterLockSlim datalock;

        public Item(Data d, RType role=RType.Normal)
        {
            datalock = new ReaderWriterLockSlim();
            data = d;
            Name = System.String.Empty;
            Role = role;
            Constant = true;
            data.Container = this;
        }

        public Item(string name, Data d, RType role=RType.Normal)
        {
            datalock=new ReaderWriterLockSlim();
            data = d;
            Name = System.String.Copy(name);
            Role = role;
            Constant = false;
            Universe.AddItem(this);
            data.Container = this;
        }

        public Data DataDirectly
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return data;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return null;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(value);
            }
        }

        public int IN
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return ((Integer)data.Convert(DType.Integer)).Value;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return 0;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(new Integer(value));
            }
        }

        public double FL
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return ((Float)data.Convert(DType.Float)).Value;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return 0;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(new Float(value));
            }
        }

        public string ST
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return ((String)data.Convert(DType.String)).Value;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return "";
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(new String(value));
            }
        }

        public List<Item> LI
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return ((List)data.Convert(DType.List)).Value;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return null;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(new List(value));
            }
        }

        public Word WO
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return (Word)data.Convert(DType.Word);
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return null;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(value);
            }
        }

        public Item RE
        {
            get
            {
                datalock.EnterReadLock();
                try
                {
                    return ((Reference)data.Convert(DType.Reference)).Value;
                }
                catch (Exception e)
                {
                    Universe.AddError(e);
                    return null;
                }
                finally
                {
                    datalock.ExitReadLock();
                }
            }

            set
            {
                Change(new Reference(value));
            }
        }

        protected virtual void Change(Data ndt)
        {
            if (Constant)
            {
                Universe.AddError(new Exception("Konstans értékét nem lehet megváltoztatni!"));
                return;
            }

            datalock.EnterWriteLock();
            try
            {
                data = ndt;
            }
            catch (Exception e)
            {
                Universe.AddError(e);
            }
            finally
            {
                datalock.ExitWriteLock();
            }
        }

        public virtual Item Clone()
        {
            datalock.EnterReadLock();
            try
            {
                if (Constant)
                    return new Item(data.Clone(), Role);
                else
                    return new Item(Name, data.Clone(), Role);
            }
            catch (Exception e)
            {
                Universe.AddError(e);
                return null;
            }
            finally
            {
                datalock.ExitReadLock();
            }

        }
        
    }
}
